####################################################################################
# Assessment Variables (EDIT THIS CODE)
####################################################################################
guide_label = "person20"
background = "cyber_chip_blue"
background_color = ""
background_sprite = ""
term_to_definition = {
# "attack surface": "all of the available attack vectors that could be used for gaining unauthorized access",
# "attack vector": "a method of gaining unauthorized access to a network or computer system",
"cyber": "involving computers or networks",
"cybersecurity": "the art of building secure computer systems that are safe from unauthorized use",
# "cybersecurity specialist": "someone who manages and maintains entire cybersecurity systems",
"digital citizenship": "the responsible and appropriate use of computing technology",
"exploit": "the process of using a system's vulnerabilities to gain unauthorized access or functionality",
# "incident and intrusion analyst": "someone who monitors networks for attacks and analyzes potential network vulnerabilities",
# "IT support": "someone who helps users with their devices and trains them to practice good computer habits",
# "network engineer": "someone who sets up, manages, and ensures secure communication of computer networks",
# "pen tester/penetration tester": "an ethical hacker who tests a system's security by hacking it (with permission!)",
# "ransomware": "a threat to publish or destroy data unless a payment is received",
"security": "having to do with being safe or secure",
# "software developer": "someone who writes computer software",
"system": "a group of related parts that affect each other and work together as a whole",
"systems thinking": "the art of thinking about how the parts of a system interact to produce an outcome",
"vulnerability": "any error, weakness, or design flaw that can be exploited by a threat actor",
}
####################################################################################
# Assessment Code (DON'T EDIT THIS CODE)
####################################################################################
import codesters
import random
from codesters.demo import Demo
from codesters import Text
demo = Demo()
stage_width = int(stage.get_stage_width())
stage_height = int(stage.get_stage_height())
def play_game(term_to_definition, rounds=0):
''' Main function that sets up and runs the game'''
global score, num_attempts
def click(sprite):
'''
Moves clicked sprite to the front (only applied to terms and definitions)
and assigns collision event when clicked.
'''
sprite.move_to_front()
sprite.event_collision(collision)
def collision(sprite, hit_sprite):
''' Collision event checks whether there is a valid match '''
if sprite.sprite_type == "definition":
sprite, hit_sprite = hit_sprite, sprite
# Immediately remove collision event as soon as it is detected
# to avoid dragging term through all matches and catching one.
# Collision event added back to sprite at the end of event.
sprite.event_collision(None)
same_group = False
term = sprite.get_text()
definition = hit_sprite.get_text()
# Check if the sprites are both terms or both definitions
same_group = sprite.sprite_type == hit_sprite.sprite_type
# Exit if term-term collision or definition-definition collision
if same_group == True:
# Add collision event before exit to allow dragging through same type and still being able to match
sprite.event_collision(collision)
return
correct_definition = term_to_definition[term]
# Correct case
if same_group == False and definition == correct_definition:
# If correct on first try, term is removed from the dictionary and next round
if sprite.attempted == False:
del term_to_definition[term]
stage.remove_sprite(sprite)
stage.remove_sprite(hit_sprite)
attempt_made("correct")
# Incorrect case
if same_group == False and definition != correct_definition:
guide.say("Nope!")
# Remove event from sprites so that they cannot
# inadvertently hit the correct sprite while gliding back
for t in term_text_sprites+definition_text_sprites:
t.event_collision(None)
stage.wait(.5)
# Mark sprite as attempted (incorrectly) so it shows in next round
sprite.attempted = True
# Send sprites back to their original locations
sprite.glide_to(sprite_to_location[sprite][0],sprite_to_location[sprite][1])
hit_sprite.glide_to(sprite_to_location[hit_sprite][0],sprite_to_location[hit_sprite][1])
attempt_made("incorrect")
def attempt_made(answer):
''' Updates stage feedback and displays win/loss results '''
global score, num_attempts
# Pause drag functionality
for t in term_text_sprites:
t.collision_off()
guide.say("")
minus_1 = Text("-1", 0, 1000, "red")
plus_1 = Text("+1", 0, 1000, "green")
if answer == "correct":
checkmark.move_to_front()
checkmark.show()
checkmark.set_position(0, 0)
correct_text.move_to_front()
correct_text.show()
correct_text.set_position(0, 135)
stage.wait(.25)
plus_1.go_to(score_text.get_x()+15, score_text.get_y())
stage.wait(.25)
plus_1.turn_right(360)
stage.remove_sprite(plus_1)
stage.wait(.25)
score += 1
score_text.set_text(str(score)+"/"+str(required_score))
stage.wait(1)
checkmark.hide()
correct_text.hide()
else:
minus_1.go_to(num_attempts_text.get_x()+15, num_attempts_text.get_y())
stage.wait(.25)
minus_1.turn_right(360)
stage.wait(.25)
stage.remove_sprite(minus_1)
num_attempts -= 1
num_attempts_text.set_text(str(num_attempts))
# Win/loss results and feedback
if num_attempts == 0:
for t in term_text_sprites+definition_text_sprites:
t.event_click(None) # only add collision event to terms
t.event_collision(None)
t.set_drag_off()
guide.move_up(50)
tester = TestManager()
# Win result
if score == required_score:
tester.display_success_message("Great job!")
if rounds > 1:
guide.say("Nice job! You won in "+str(rounds)+" rounds!\n\nClick RUN to try and beat your score!")
else:
guide.say("Excellent job! You won in just 1 round!")
# Remind student to submit and click next
reminder_sprites = demo.remind_student_to_submit(guide.get_x() - 180, guide.get_top() + 100, 25)
# Flash the reminder sprites
for counter in range(5):
for sprite in reminder_sprites:
sprite.set_opacity(.7)
stage.wait(0.2)
for sprite in reminder_sprites:
sprite.set_opacity(1)
stage.wait(0.2)
# Loss result
else:
# Create next button and label
next_round_button = codesters.Rectangle(0, 150, -(label_x - display_x), 30, "#f1823b")
next_round_button.collision_off()
next_symbol = u"⇨"
next_round_button_text = Text("NEXT ROUND"+next_symbol, next_round_button.get_x(), next_round_button.get_y(), "white")
next_round_button_text.collision_off()
next_round_button_text.set_text_width(-(label_x - display_x))
next_round_button_text.set_text_align("center")
next_round_button_text.set_text_size(17)
demo.add_hover_opacity_element(next_round_button)
next_round_button.event_click(reset_click)
guide.move_to_front()
guide.set_say_background("#eee", 1)
tester.display_failure_message("Almost! Click the NEXT ROUND button to move on to Round "+str(rounds+1)+".")
guide.say("Almost! Click the NEXT ROUND button to move on to Round "+str(rounds+1)+".\n\nMatch a term correctly on the first try so that it doesn't appear in the next round.")
############################
# Main function begins here
############################
rounds += 1
required_score = len(term_to_definition)
# Set up stage
if background:
stage.set_background(background)
if background_color:
stage.set_background_color(background_color)
if background_sprite:
bg_sprite = codesters.Sprite(background_sprite, 0, 0)
bg_sprite.collision_off()
bg_sprite.set_height(stage_height)
bg_sprite.set_width(stage_width)
guide = demo.create_sprite_off_screen(guide_label, 0, -200, 1)
guide.set_bottom(-stage_height/2)
# Create checkmark offscreen
checkmark = codesters.Sprite("checkmark_0bf", 1000, 0)
correct_text = Text("CORRECT", 1000, 0, "green")
correct_text.set_text_size(50)
correct_text.set_text_weight('bold')
#######################################
# Introduction screen
#######################################
# Intro explanation in the first round
if rounds == 1:
guide.say("Welcome to Vocab Match!")
stage.wait(2)
guide.say("Welcome to Vocab Match!\n\nLet's test your vocabulary knowledge.")
stage.wait(2)
demo.continue_action()
guide.say("Drag the terms and definitions together to match them!")
stage.wait(2)
guide.say("Drag the terms and definitions together to match them!\n\nAny terms not matched correctly\n on the first try will appear in the next round.")
demo.continue_action()
########################################
# Assessment begins here
########################################
guide.say("Round "+str(rounds)+"!")
guide.move_down(50)
label_x = -70 # left aligned
display_x = 70 # right aligned
# Round display
round_label_text = Text("ROUND: ", label_x, 250,"black")
round_label_text.set_text_align("left")
round_text = Text(str(rounds), display_x, round_label_text.get_y(), "black")
round_text.set_text_align("right")
# Score display
score = 0
score_label_text = Text("SCORE: ", label_x, 220,"black")
score_label_text.set_text_align("left")
score_text = Text(str(score)+"/"+str(required_score), display_x, score_label_text.get_y(),"green")
score_text.set_text_align("right")
# Attempts display
num_attempts = len(term_to_definition)
num_attempts_label_text = Text("TRIES LEFT: ", label_x, 190, "black")
num_attempts_label_text.set_text_align("left")
num_attempts_text = Text(str(num_attempts), display_x, num_attempts_label_text.get_y(), "red")
num_attempts_text.set_text_align("right")
# Turn collision off for all stage objects that are not part of game
stage_objects = [guide, checkmark, correct_text, round_label_text, round_text, score_label_text, score_text, num_attempts_label_text, num_attempts_text]
for s in stage_objects:
s.collision_off()
# Store text sprites in separate lists
term_text_sprites = []
definition_text_sprites = []
# Store total heights of text sprites
terms_total_height = 0
definitions_total_height = 0
# Create term and definition sprites from main dict
for key in term_to_definition:
# Create term sprites
term = codesters.Text(key, 0, 1000)
terms_total_height += term.get_height()
term_text_sprites.append(term)
# Create definition sprites
definition = codesters.Text(term_to_definition[key], 0, 1000)
definition.set_text_width(350)
definitions_total_height += definition.get_height()
definition_text_sprites.append(definition)
# Randomize order of terms and sprites
random.shuffle(term_text_sprites)
random.shuffle(definition_text_sprites)
# Stores initial sprite locations
sprite_to_location = {}
# Variables for positioning sprites
top_y = 250 # Highest point for stage items
num_terms = len(term_to_definition)
available_y = stage_height - (stage_height/2-top_y)
term_avg_height = terms_total_height/num_terms
definition_avg_height = definitions_total_height/num_terms
# Calculate padding for terms and definitions
term_padding = (available_y-term_avg_height*num_terms)/num_terms
definition_padding = (available_y-definition_avg_height*num_terms)/num_terms
# Initial top point for all sprites
term_top = definition_top = top_y
if num_terms < 7:
term_top = top_y-.5*term_padding
definition_top = top_y-.5*definition_padding
# Set up term sprites
for t in term_text_sprites:
# t.event_collision(collision) # only add collision event to terms
t.sprite_type = "word"
t.attempted = False
t.set_text_background("lightblue", "black", .85)
t.set_text_align("left")
t.set_speed(15)
t.set_drag_on()
t.event_click(click)
t.collision_on()
t.set_x(-500)
t.set_top(term_top)
sprite_to_location[t] = (t.get_x(), t.get_y())
# Update next top to the bottom of the last term
term_top = t.get_bottom() - term_padding
# Set up definition sprites
for d in definition_text_sprites:
d.sprite_type = "definition"
d.set_text_background("orange", "black", .85)
d.set_text_align("left")
d.set_speed(15)
d.set_drag_on()
d.event_click(click)
d.collision_on()
d.set_x(150)
d.set_top(definition_top)
sprite_to_location[d] = (d.get_x(), d.get_y())
# Update next top to the bottom of the last definition
definition_top = d.get_bottom() - definition_padding
# Click event for reset button
def reset_click(sprite):
sprites = stage.get_all_sprites()
for s in sprites:
stage.remove_sprite(s)
play_game(term_to_definition, rounds)
play_game(term_to_definition)